package cn.virens.common.project.generator.connection;

import cn.virens.common.util.exception.APIException;
import com.alibaba.druid.pool.DruidDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.SQLException;

public class DatabaseManagerImpl implements DatabaseManager {
    private final Logger logger = LoggerFactory.getLogger(DatabaseManagerImpl.class);

    private final ThreadLocal<DatabaseConnoction> local = new ThreadLocal<>();

    private final DruidDataSource dataSource = new DruidDataSource();

    private String jdbcDriverClass;
    private String jdbcPassword;
    private String jdbcUsername;
    private String jdbcUrl;

    public String getJdbcUrl() {
        return jdbcUrl;
    }

    public void setJdbcUrl(String jdbcUrl) {
        this.jdbcUrl = jdbcUrl;
    }

    public String getJdbcUsername() {
        return jdbcUsername;
    }

    public void setJdbcUsername(String jdbcUsername) {
        this.jdbcUsername = jdbcUsername;
    }

    public String getJdbcPassword() {
        return jdbcPassword;
    }

    public void setJdbcPassword(String jdbcPassword) {
        this.jdbcPassword = jdbcPassword;
    }

    public String getJdbcDriverClass() {
        return jdbcDriverClass;
    }

    public void setJdbcDriverClass(String jdbcDriverClass) {
        this.jdbcDriverClass = jdbcDriverClass;
    }

    @Override
    public DatabaseConnoction getConnection() throws SQLException {
        DatabaseConnoction conn = local.get();

        // 连接不存在 | 连接被关闭
        if (conn == null || conn.isClosed()) {
            local.set(conn = new DatabaseConnoction(dataSource));
        }

        return conn;
    }

    @Override
    public DatabaseManager execute(DatabaseQueryExecute execute) {
        DatabaseConnoction connoction = null;

        try {
            connoction = getConnection();
            connoction.setAutoCommit(true);

            // 执行查询
            execute.execute(connoction);
        } catch (Exception e) {
            logger.error("SQL异常:" + e.getMessage(), e);
        }

        return this;
    }

    @Override
    public DatabaseManager transactionExecute(DatabaseQueryExecute execute) {
        DatabaseConnoction connoction = null;

        try {
            connoction = getConnection();
            connoction.setAutoCommit(false);

            // 执行查询
            execute.execute(connoction);

            // 提交查询
            connoction.commit();
        } catch (Exception e) {
            logger.error("SQL异常:" + e.getMessage(), e);

            try {
                connoction.rollback();
            } catch (Exception e2) {
                logger.error("回滚异常:" + e2.getMessage(), e2);
            }
        }

        return this;
    }

    public void initialize() throws APIException, SQLException {
        this.dataSource.setDriverClassName(getJdbcDriverClass());
        this.dataSource.setPassword(getJdbcPassword());
        this.dataSource.setUsername(getJdbcUsername());
        this.dataSource.setUrl(getJdbcUrl());

        // 配置初始化大小、最小、最大
        this.dataSource.setMinIdle(1);
        this.dataSource.setInitialSize(1);
        this.dataSource.setMaxWait(60000);// 配置获取连接等待超时的时间
        this.dataSource.setMaxActive(1000);

        this.dataSource.setFilters("slf4j");

        this.dataSource.setTestOnBorrow(false);
        this.dataSource.setTestOnReturn(false);
        this.dataSource.setTestWhileIdle(true);

        this.dataSource.setValidationQuery("SELECT 1;");
        this.dataSource.setValidationQueryTimeout(30000);

        this.dataSource.setMinEvictableIdleTimeMillis(300000);// 配置一个连接在池中最小生存的时间，单位是毫秒
        this.dataSource.setTimeBetweenEvictionRunsMillis(60000);// 配置间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒
    }

    public void destroy() throws APIException {
        this.dataSource.close();
    }

    @Override
    public void close() throws APIException {
        DatabaseConnoction connoction = local.get();
        if (connoction == null) return;

        connoction.close();
        local.remove();
    }
}
